﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Text;
using System.Xml;
using Common.Utilities;
using Common.Utilities.Dispatcher;
using Common.Utilities.DLR;
using Workflows.Components.Reports.Properties;

namespace Workflows.Components.Reports
{
    /// <summary></summary>
    [Serializable]
    public class ExcelReportComponent:WorkflowComponentBase
    {
        #region props
        private ExcelReportInstruction _Instruction;
        private ExcelReportOutput _Output;

        public override InstructionBase Instruction
        {
            get { return _Instruction; }
            set { _Instruction =(ExcelReportInstruction) value; }
        }

        public override ResultBase Output
        {
            get { return _Output; }
            set { _Output =(ExcelReportOutput) value; }
        }

        /// <summary></summary>
        [OrmField("Name", SqlDbType.VarChar, 100, OrmFieldSerializationMethod.DefaultSerialization)]
        public string ReportName
        {
            get { return _Instruction.ReportName; }
            set { _Instruction.ReportName = value; }
        }

        /// <summary></summary>
        [OrmField("ConnectionString", SqlDbType.VarChar, 100, OrmFieldSerializationMethod.DefaultSerialization)]
        public string ConnectionString
        {
            get { return _Instruction.ConnectionString; }
            set { _Instruction.ConnectionString = value; }
        }

        /// <summary></summary>
        [OrmField("_ParameterNameValues", SqlDbType.Text, 1000, OrmFieldSerializationMethod.BinarySerialization)]
        public Dictionary<string, string> ParameterNameValues
        {
            get { return _Instruction.ParameterNameValues; }
            set { _Instruction.ParameterNameValues = value; }
        }

        /// <summary></summary>
        [OrmField("WorksheetNames", SqlDbType.VarChar, 1000, OrmFieldSerializationMethod.BinarySerialization)]
        public List<string> WorksheetNames
        {
            get { return _Instruction.WorksheetNames; }
            set { _Instruction.WorksheetNames = value; }
        }

        /// <summary></summary>
        [OrmField("DataRegions", SqlDbType.Text, 1000, OrmFieldSerializationMethod.BinarySerialization)]
        public List<ExcelDataRegion> DataRegions
        {
            get { return _Instruction.DataRegions; }
            set { _Instruction.DataRegions = value; }
        }

        /// <summary></summary>
        [OrmField("Template", SqlDbType.Text, 1000, OrmFieldSerializationMethod.BinarySerialization)]
        public string Template
        {
            get { return _Instruction.Template; }
            set { _Instruction.Template = value; }
        }

        /// <summary></summary>
        public string ReportFilePath
        {
            get
            {
                return this._Instruction.ReportFilePath;
            }
            set
            {
                this._Instruction.ReportFilePath = value;
            }
        }
        #endregion

        /// <summary></summary>
        public ExcelReportComponent():base()
        {
            this.ComponentActivityType = WorkflowActivityType.SimpleActivity;
            this.ComponentCategory = WorkflowComponentCategory.Report_Tasks.ToString();
            this.ComponentIcon = Resources.excel_file;
            this.ComponentImage = Resources.utility;
            this.ComponentName = "Excel Report";
            this.Description = "Define excel report template and data bindings using sql select statement";

            this._Instruction = new ExcelReportInstruction(this.ComponentID,Guid.Empty,string.Empty);
            this._Output=new ExcelReportOutput(this.ComponentID,Guid.Empty,string.Empty);
        }

        public override XmlNode Serialize(ref XmlDocument xDoc, ref XmlNode parentNode)
        {
            XmlNode xNode = base.Serialize(ref xDoc, ref parentNode);

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ReportName", this.ReportName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ReportFilePath", this.ReportFilePath);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ConnStr", this.ConnectionString);
            if (this.ParameterNameValues != null && this.ParameterNameValues.Count > 0)
            {
                XmlNode paramRootNode = XmlDataUtil.AddElement(ref xDoc, xNode, "Parameters");
                foreach (string paramName in this.ParameterNameValues.Keys)
                {
                    XmlNode paramNode = XmlDataUtil.AddElement(ref xDoc, paramRootNode, "Parameter");
                    XmlDataUtil.UpdateAttribute(ref xDoc, paramNode, "ParameterName", paramName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, paramNode, "ParameterValue", this.ParameterNameValues[paramName]);
                }
            }
            if (this.WorksheetNames != null && this.WorksheetNames.Count > 0)
            {
                XmlNode worksheetRootNode = XmlDataUtil.AddElement(ref xDoc, xNode, "Worksheets");
                foreach (string wksheetName in this.WorksheetNames)
                {
                    XmlNode worksheetNode = XmlDataUtil.AddElement(ref xDoc, worksheetRootNode, "Worksheet");
                    XmlDataUtil.UpdateAttribute(ref xDoc, worksheetNode, "Name", wksheetName);
                }
            }
            if (this.DataRegions != null && this.DataRegions.Count > 0)
            {
                XmlNode dataReagionRootNode = XmlDataUtil.AddElement(ref xDoc, xNode, "DataRegions");
                foreach (ExcelDataRegion region in this.DataRegions)
                {
                    XmlNode regionNode = XmlDataUtil.AddElement(ref xDoc, dataReagionRootNode, "DataRegion");
                    XmlDataUtil.UpdateAttribute(ref xDoc, regionNode, "WorksheetName", region.WorksheetName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, regionNode, "Range", region.Range);
                    XmlDataUtil.UpdateAttribute(ref xDoc, regionNode, "Sql", region.Sql);
                    XmlDataUtil.UpdateAttribute(ref xDoc, regionNode, "FillAction", ((int)region.FillAction).ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, regionNode, "KeyPosition", region.KeyPosition);
                    XmlDataUtil.UpdateAttribute(ref xDoc, regionNode, "KeyName", region.KeyName);
                    if (region.ExcelColumnBindings != null && region.ExcelColumnBindings.Count > 0)
                    {
                        foreach (string dataFieldName in region.ExcelColumnBindings.Keys)
                        {
                            XmlNode bindingNode = XmlDataUtil.AddElement(ref xDoc, regionNode, "Binding");
                            XmlDataUtil.UpdateAttribute(ref xDoc, bindingNode, "DataFieldName", dataFieldName);
                            XmlDataUtil.UpdateAttribute(ref xDoc, bindingNode, "ExcelColName", region.ExcelColumnBindings[dataFieldName]);
                        }
                    }
                }
            }
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "Template",
                                         Base64Util.EncodeAsBase64(Encoding.Default.GetBytes(this.Template)));

            return xNode;
        }

        public override WorkflowComponentBase Instantiate(XmlNode xNode)
        {
            if (xNode.Attributes.GetNamedItem("Type").Value == this.GetType().FullName)
            {
                ExcelReportComponent component = base.Instantiate(xNode) as ExcelReportComponent;

                component.ReportName = XmlDataUtil.GetAttributeValue(xNode, "ReportName", "");
                component.ReportFilePath = XmlDataUtil.GetAttributeValue(xNode, "ReportFilePath", "");
                component.ConnectionString = XmlDataUtil.GetAttributeValue(xNode, "ConnStr", "");
                XmlNodeList paramNodes = xNode.SelectNodes("Parameters/Parameter");
                if (paramNodes != null && paramNodes.Count > 0)
                {
                    component.ParameterNameValues = new Dictionary<string, string>();
                    foreach (XmlNode paramNode in paramNodes)
                    {
                        string paramName = XmlDataUtil.GetAttributeValue(paramNode, "ParameterName", "");
                        string paramValue = XmlDataUtil.GetAttributeValue(paramNode, "ParameterValue", "");
                        component.ParameterNameValues.Add(paramName, paramValue);
                    }
                }
                XmlNodeList wksheetNodes = xNode.SelectNodes("Worksheets/Worksheet");
                if (wksheetNodes != null && wksheetNodes.Count > 0)
                {
                    component.WorksheetNames = new List<string>();
                    foreach (XmlNode wksheetNode in wksheetNodes)
                    {
                        component.WorksheetNames.Add(XmlDataUtil.GetAttributeValue(wksheetNode, "Name", ""));
                    }
                }
                XmlNodeList regionNodes = xNode.SelectNodes("DataRegions/DataRegion");
                if (regionNodes != null && regionNodes.Count > 0)
                {
                    component.DataRegions = new List<ExcelDataRegion>();
                    foreach (XmlNode regionNode in regionNodes)
                    {
                        ExcelDataRegion region = new ExcelDataRegion();
                        region.WorksheetName = XmlDataUtil.GetAttributeValue(regionNode, "WorksheetName", "");
                        region.Range = XmlDataUtil.GetAttributeValue(regionNode, "Range", "");
                        region.Sql = XmlDataUtil.GetAttributeValue(regionNode, "Sql", "");
                        region.FillAction =
                            (ExcelDataFillAction)int.Parse(
                                                      XmlDataUtil.GetAttributeValue(
                                                          regionNode, "FillAction",
                                                          ((int)ExcelDataFillAction.FillValue).ToString()));
                        region.KeyPosition = XmlDataUtil.GetAttributeValue(regionNode, "KeyPosition", "");
                        region.KeyName = XmlDataUtil.GetAttributeValue(regionNode, "KeyName", "");
                        region.ExcelColumnBindings = new Dictionary<string, string>();
                        XmlNodeList bindingNodes = regionNode.SelectNodes("Binding");
                        if (bindingNodes != null && bindingNodes.Count > 0)
                        {
                            foreach (XmlNode bindingNode in bindingNodes)
                            {
                                string dataFieldName = XmlDataUtil.GetAttributeValue(bindingNode, "DataFieldName", "");
                                string excelColName = XmlDataUtil.GetAttributeValue(bindingNode, "ExcelColName", "");
                                region.ExcelColumnBindings.Add(dataFieldName, excelColName);
                            }
                        }
                        component.DataRegions.Add(region);
                    }
                }
                component.Template =
                    Encoding.Default.GetString(
                        Base64Util.DecodeAsBytes(XmlDataUtil.GetAttributeValue(xNode, "Template", "")));

                return component;
            }
            else
            {
                throw new Exception("Unable to instantiate component: invalid type specified in xml node");
            }
        }
    }
}
